#include "StringUtil.h"




StringUtil::StringUtil ()
{
}

String StringUtil::toLowerCase (const String& string)
{
	String str = string;

	String::iterator it;
	for (it = str.begin(); it != str.end(); it++)
	{
		*it = tolower (*it);
	}
	return str;
}

void StringUtil::toLowerCase (String& string)
{
	String::iterator it;
	for (it = string.begin(); it != string.end(); it++)
	{
		*it = tolower (*it);
	}
}

StringArray StringUtil::split (const String& str, Char delimiter)
{
	StringArray ret;
	
	int nextPos=-1;
	int prevPos=-1;
	while (true)
	{
		prevPos = nextPos;
		nextPos = str.find (delimiter, nextPos+1);

		if (nextPos == String::npos)
		{
			String tmp = str.substr (prevPos+1);
			if (tmp != _T("") && tmp != _T(" "))
				ret.push_back (tmp);

			break;
		}

		ret.push_back (str.substr (prevPos+1, nextPos - prevPos-1));
	}
	return ret;
}


StringArray StringUtil::splitMulti (const String& str, const String& delimeters)
{
	const Char *dt = str.c_str();
	const Char *del = delimeters.c_str();
	u32 lastSplit=0;
	StringArray ret;
	
	for (u32 i=0; i<str.length(); i++)
	{
		for (u32 j=0; j<delimeters.length(); j++)
		{
			if (dt [i] == del[j])
			{
				//split here
				if (i - lastSplit == 0)
				{
					lastSplit = i+1;
					break;
				}

				ret.push_back (str.substr (lastSplit, i - lastSplit));
				lastSplit = i+1;
				break;
			}
		}
	}

	if (ret.size() == 0)
		ret.push_back (str);

	return ret;
}

String StringUtil::toString (float value, u16 precision)
{
	OStringStream strm;

	strm.precision (precision);
	strm << value;
	return strm.str ();
}

String StringUtil::toString (u32 value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (u16 value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (i16 value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (i32 value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (u64 value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (i64 value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (double value)
{
	OStringStream strm;

	strm << value;
	return strm.str ();
}

String StringUtil::toString (bool value)
{
	if (value)
		return _T("True");

	return _T("False");
}

String StringUtil::toString (const byte *data)
{
	StringA tmp = StringA ((char*)data);
	return StringUtil::makeString (tmp);
}


String StringUtil::getFileName (const String& filePath)
{
	//Extract the file name from a file path
	size_t loc = filePath.find_last_of (_T("\\"));

	if (loc == String::npos)
		return String (_T(""));

	return filePath.substr (loc + 1, filePath.length ());
}

String StringUtil::getFileExtension (const String& filePath)
{
	size_t loc = filePath.find (_T('.'));

	if (loc == String::npos)
		return _T("");

	return filePath.substr (loc+1, filePath.length());
}

i32 StringUtil::parseInt (const String& string)
{
	return _tstoi (string.c_str ());
}

u32 StringUtil::parseUInt (const String& string)
{
	return static_cast <u32> (_tcstoul (string.c_str (), NULL, 10));
}


StringA StringUtil::unicodeToANSI (const StringW& unicodeString)
{
	const wchar_t *strW;
	char *strA;
	StringA str;

	strW = unicodeString.c_str ();

	i32 bufSize = WideCharToMultiByte (CP_ACP, 0, strW, -1, NULL, 0,NULL,NULL);
	strA = new char [bufSize];

	WideCharToMultiByte (CP_ACP, 0, strW, -1, strA, bufSize,NULL,NULL);

	str = StringA (strA);
	delete [] strA;
	return str;
}


StringW StringUtil::ansiToUnicode (const StringA& ansiString)
{
	const char *strA;
	wchar_t *strW;
	StringW str;

	strA = ansiString.c_str();

	i32 bufSize = MultiByteToWideChar (CP_ACP, 0, strA, -1, NULL, 0);
	strW = new wchar_t [bufSize];

	MultiByteToWideChar (CP_ACP, 0, strA, -1, strW, bufSize);

	str = StringW (strW);
	delete []strW;
	return str;

}


float StringUtil::parseFloat (const String& string)
{
	return static_cast <float> (_tstof (string.c_str ()));
}

double StringUtil::parseDouble (const String& string)
{
	return _tstof (string.c_str ());
}

static bool parseBool (const String& string)
{
	return (string == _T("True") || string == _T("true"));
}


String StringUtil::makeString (const StringA& str)
{
	#ifdef _UNICODE
		return (String)ansiToUnicode (str);
	#else
		return (String) str;
	#endif
}

StringA StringUtil::makeANSI (const String& anyStringType)
{
	#ifdef _UNICODE
		return unicodeToANSI ((StringW) anyStringType);
	#else
		return (StringA) anyStringType;
	#endif
}

StringW StringUtil::makeUnicode (const String& anyStringType)
{
	#ifdef _UNICODE
		return (StringW) anyStringType;
	#else
		return StringUtil::ansiToUnicode ((StringA) anyStringType);
	#endif
}

String StringUtil::makeString (const StringW& str)
{
	#ifdef _UNICODE
		return (String) str;
	#else
		return (String) unicodeToANSI (str);
	#endif
}

String StringUtil::urlDecode (const String& urlEncodedString)
{
	return urlEncodedString;
}


u32 StringUtil::LevenshteinDistance (const String& str1, const String& str2)
{
    u32 totSize = (str1.length()+1)*(str2.length()+1);
    u32 rowSize = str2.length() + 1;
    
    u32 *raw = new u32 [totSize];

    const Char *s1 = str1.c_str();
    const Char *s2 = str2.c_str();
    for (u32 i=0; i<totSize; i++)
        raw [i] = 0.0f;

    for (u32 i=0; i<str1.length()+1; i++)
        raw [i*rowSize] = i;
    
    for (u32 j=0; j<str2.length()+1; j++)
        raw [j] = j;

    for (u32 i=1; i<str1.length()+1; i++)
    {
        for (u32 j=1; j<str2.length()+1; j++)
        {
            if (s1 [i] == s2[j])
                raw [i*rowSize+j] = raw [(i-1)*rowSize + (j-1)];
            else
                raw [i*rowSize+j] = min (min (raw [(i-1)*rowSize+j]+1, raw [i*rowSize+(j-1)]+1), raw [(i-1)*rowSize+(j-1)]+1);
        }
    }
    u32 ret = raw [(str1.length()*rowSize) + str2.length()];
    delete []raw;
    return ret;
}